package hyl.base.net.iot;

import java.nio.charset.Charset;
import java.util.ArrayList;

import hyl.core.MyCharset;
import hyl.core.MyFun;
import hyl.core.data.Bytes;
import hyl.core.fun.MyByte;

/**
 * 
 * 用于客户集群与中央之间的级联分布式指令
 * 
 * A发给b,b发给c,c发给d
 * 
 * 注意:只要考虑粘包设计,不需要考虑丢包设计(因为tcp层已经解决了)
 * 
 * 至于网络中断,也不要考虑,如果终端 网络必须断开,.socket 不可复用
 * 
 * @author 37798955@qq.com
 *
 */
public class Netpg3 {
	public int[] ii路径 = null;
	public byte b指令1 = 0;//为0时 启用扩展
	public byte b指令2 = 0;//扩展
	public byte b指令3 = 0;//扩展
	public byte b指令4 = 0;//扩展
	public Charset c结果编码 = null;
	// 如果把路径+指令作为 map的key
	public String s请求 = null; // 指令不能作为int 因为 open=10;这样的指令是带有参数的
	public byte[] bb反馈 = null;
	// 协议
	public static final byte CMD_UNKNOW = 0;
	public static final byte CMD_注册 = 1;
	public static final byte CMD_心跳 = 2;
	public static final byte CMD_D注册 = 3;
	public static final byte CMD_D心跳 = 4;
	public static final byte CMD_B注册 = 5;
	public static final byte CMD_B心跳 = 6;
	public static final byte CMD_D离线 = 10;
	public static final byte CMD_C离线 = 11;
	public static final byte CMD_B离线 = 12;
	public static final byte CMD_A离线 = 13;
	public static final byte CMD_文本 = 20;
	public static final byte CMD_字节 = 21;


	public Netpg3() {

	}

	public boolean existPath() {
		return ii路径 != null && ii路径.length > 0;
	}

	public int getDid() {
		return ii路径[0];
	}

	public Bytes getPaths() {
		if (ii路径 == null || ii路径.length== 0)
			return  null;
		return Bytes.wrap(path2bytes(ii路径));
	}

	public Bytes getKey() {

		byte[] b1 = path2bytes(ii路径);
		byte[] b2 = req2bytes(s请求);
		
		return  Bytes.wrap(MyFun.concat(b1, b2));
	}

	public Netpg3(byte[] data) {
		deserial(data);
	}

	public byte[] serial() {
		// 总长度 (4)+ (指令1~4,编码,路径长度,请求长度,路径,请求,反馈)
		byte[] b1 = path2bytes(ii路径);
		// MyFun.byteArray2Str(data,MyCharset._UTF8);
		byte[] b2 = req2bytes(s请求);
	
		
		int len1= (b1 == null) ? 0 : b1.length;
		int len2= (b2 == null) ? 0 : b2.length;
		int len3= (bb反馈 == null) ? 0 : bb反馈.length;
		byte[] l1 = MyFun.int2ByteArray(len1);// 路径
		byte[] l2 = MyFun.int2ByteArray(len2);// 请求
		
		int len = 5 + 4 + 4 + len1 + len2 + len3;
		byte[] l0 = MyFun.int2ByteArray(len);
		return MyFun.concat(l0, new byte[] { b指令1, b指令2, b指令3, b指令4, charset2byte() }, l1, l2, b1, b2, bb反馈);
	}

	public byte[] deserial(byte[] data1) {
		/**
		 * D/C/B = <br>
		 * l0 总长度(4) =1+4+4+4+l1+l2+l3 <br>
		 * 指令 +结果编码<br>
		 * l1 路径长度（2）+D（2）+C（2）+B（2） <br>
		 * l2 请求长度（2）+请求 <br>
		 * 反馈结果<br>
		 */
		int l0 = MyFun.byteArray2Int(MyByte.subBytes(data1, 0, 4));
		byte[] data = MyByte.subBytes(data1, 4, l0);
		b指令1 = data[0];
		b指令2 = data[1];
		b指令3 = data[2];
		b指令4 = data[3];
		c结果编码 = bytes2charset(data[4]);
		int l1 = MyFun.byteArray2Int(MyByte.subBytes(data, 5, 4)); // 路径长度
		int l2 = MyFun.byteArray2Int(MyByte.subBytes(data, 9, 4)); // 请求长度

		int start = 13;
		if (l1 == 0)
			ii路径 = null;
		else
			ii路径 = bytes2path(MyByte.subBytes(data, start, l1));
		start += l1;
		if (l1 == 0)
			s请求 = null;
		else
			s请求 = bytes2req(MyByte.subBytes(data, start, l2));
		start += l2;
		if (data.length == start)
			bb反馈 = null;
		else
			bb反馈 = MyByte.subBytes(data, start);
		return MyByte.subBytes(data1, 4 + l0);

	}

	byte charset2byte() {
		return c结果编码 == MyCharset._ASCII ? (byte) 1 : c结果编码 == MyCharset._UTF8 ? (byte) 2:(byte)0;
	}

	Charset bytes2charset(byte data) {
		return data == 2 ? MyCharset._UTF8 :data == 1 ? MyCharset._ASCII:null;
	}

	String bytes2req(byte[] data) {
		return MyFun.bytes2Str(data, MyCharset._UTF8);
	}

	byte[] req2bytes(String cmd) {
		return MyFun.str2Bytes(cmd, MyCharset._UTF8);
	}

	int[] bytes2path(byte[] data) {
		int pathlen = data.length;
		int pathnum = pathlen / 4;
		int[] ps = new int[pathnum];
		for (int i = 0, j = 0; i < pathlen; i += 4) {
			ps[j] = MyFun.byteArray2Int(MyByte.subBytes(data, i, 4));
			j++;
		}
		return ps;
	}

	byte[] path2bytes(int[] data) {
		ArrayList<byte[]> bs = new ArrayList<byte[]>(data.length);
		for (int a : data) {
			bs.add(MyFun.int2ByteArray(a));
		}
		return MyFun.concatlb(bs);
	}
	public void set(int[] 路径,  byte 指令1) {
		this.ii路径 = 路径;
		this.b指令1 = 指令1;
	}
	public void set(int[] 路径,  byte 指令1, String 请求,  Charset 数据编码,byte[] 结果) {
		this.ii路径 = 路径;
		this.c结果编码 = 数据编码;
		this.s请求 = 请求;
		this.b指令1 = 指令1;
		this.bb反馈 = 结果;
	}

	public void set指令(byte... 指令) {
		if (指令 == null)
			return;
		if (指令.length > 0)
			this.b指令1 = 指令[0];
		if (指令.length > 1)
			this.b指令2 = 指令[1];
		if (指令.length > 2)
			this.b指令3 = 指令[2];
		if (指令.length > 4)
			this.b指令4 = 指令[3];
	}
	public String getS反馈() {
		if (c结果编码==null)
			return MyByte.bytesToBin(bb反馈); 
		return MyFun.bytes2Str(bb反馈, c结果编码);
	}
	public String toString() {
		String s = MyFun.join("指令=", b指令1,";s请求=\"",this.s请求,"\";反馈=\"", getS反馈() );
		return s;
	}

}
